//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Research.eResearch.Common.Logging;
using TridentScheduleCommon;
using WFServiceLibrary;

namespace WFServiceTrayApp
{
    public partial class WFTrayForm : Form
    {
        private AboutBox aboutWindow;
        public WFTrayForm()
        {
            InitializeComponent();

            WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;
            LoadWFService();
        }

        #region Private Methods

        /// <summary>
        /// This method spawns a new Thread which will poll
        /// the registry to look for new WF's to run. 
        /// </summary>
        private void LoadWFService()
        {
            Log("Info", "Attempting to start WF Execution Tray App...");

            Environment.CurrentDirectory = System.AppDomain.CurrentDomain.BaseDirectory;

            // Configure the Scheduler with the details.
            scheduler = new WFServiceScheduler();
            scheduler.HostName = System.Environment.MachineName;
            scheduler.WFProcessName = ConfigurationSettings.AppSettings["WFApp"];
            scheduler.ShowConsole = showConsoleToolStripMenuItem.Checked;
            scheduler.OnLaunchWorkflow += new EventHandler<WFLauchEventArgs>(scheduler_OnLaunchWorkflow);
            scheduler.OnTerminateScheduler += new WFServiceScheduler.TerminateSchedulerEvent(scheduler_OnTerminateScheduler);
            scheduler.LogMessageReceived += new EventHandler<LogEventArgs>(this.OnLogMessageReceived);
            scheduler.IsInteractiveExecution = true;
            string attempts = ConfigurationSettings.AppSettings["SQLReconnectAttempts"];
            if (!string.IsNullOrEmpty(attempts))
            {
                scheduler.configurableReconnectAttempts = Int32.Parse(attempts);
            }

            // Start New thread for Running the pending workflows.
            this.scheduleThread = new Thread(scheduler.RunWorkflows);
            this.scheduleThread.Start();

            // Create WindowsTaskCreater thread
            WindowsTaskCreator taskCreater = new WindowsTaskCreator();
            string SchedulerPollTime = ConfigurationSettings.AppSettings["SchedulerPollTimeInMilliseconds"];
            taskCreater.SchedulerEXEPath =
                Path.Combine(Environment.CurrentDirectory, ConfigurationSettings.AppSettings["SchedulerEXE"]);

            taskCreater.HostName = scheduler.HostName;
            taskCreater.IsInteractiveExecution = true;
            if (!string.IsNullOrEmpty(SchedulerPollTime))
                taskCreater.SchedulerPollTime = Int32.Parse(SchedulerPollTime);

            taskCreater.LogMessageReceived += new EventHandler<LogEventArgs>(this.OnLogMessageReceived);

            // Start New thread for updating scheduler information.
            this.scheduleUpdaterThread = new Thread(taskCreater.RunScheduleCreationThread);
            this.scheduleUpdaterThread.Start();

            Log("Info", "WF Execution Tray App started successfully.");
        }

        void scheduler_OnTerminateScheduler(string message)
        {
            MessageBox.Show(message + "\r\nTray app will be closed, please resolve the issue and restart it again.", "Trident Execution Tray", MessageBoxButtons.OK, MessageBoxIcon.Stop);

            Process process = Process.GetCurrentProcess();
            process.CloseMainWindow();

            closedByUser = false;
            ShutdownService();
        }

        void scheduler_OnLaunchWorkflow(object sender, WFLauchEventArgs args)
        {
            NotifyIcon.ShowBalloonTip(10,
                string.Format("Workflow Launched"),
                string.Format("Launch workflow: {0}", args.WorkflowName),
                ToolTipIcon.Info);
        }

        private void WFTrayForm_Resize(object sender, EventArgs e)
        {
            if (FormWindowState.Minimized == WindowState)
                Hide();
        }

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ShowAboutWindow();
        }

        /// <summary>
        /// Shows the about window
        /// </summary>
        private void ShowAboutWindow()
        {
            if ((this.aboutWindow == null) || (this.aboutWindow != null && this.aboutWindow.IsVisible == false)) ////If the AboutWindow is not initialized or AboutWindow is initialized but closed/invisible
            {
                this.aboutWindow = new AboutBox();
            }
            if (this.aboutWindow.IsVisible == false) ////If it is not visible bring it into view
            {
                this.aboutWindow.ShowDialog();
            }
            else ////Already AboutWindow is visble but user is selecting again, just activate the window
            {
                this.aboutWindow.Activate();
            }
        }

        private void WFTrayForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            try
            {
                // Stop the WF polling thread.
                if (null != this.scheduleUpdaterThread && this.scheduleUpdaterThread.IsAlive)
                {
                    this.scheduleUpdaterThread.Abort();
                }

                if (null != this.scheduleThread && this.scheduleThread.IsAlive)
                {
                    this.scheduleThread.Abort();
                }
            }
            catch (Exception ex)
            {
                Log("Error", ex.Message);
            }
            finally
            {
                Application.Exit();
                Log("Info", "Exiting the Tray App");
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            closedByUser = true;
            ShutdownService();
        }

        private void ShutdownService()
        {
            WFTrayForm_FormClosed(null, null);
        }

        private void showConsoleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            showConsoleToolStripMenuItem.Checked = !showConsoleToolStripMenuItem.Checked;
            scheduler.ShowConsole = showConsoleToolStripMenuItem.Checked;
        }

        private void WFTrayForm_Closing(object sender, FormClosingEventArgs e)
        {
            //No need to promt this when invoked from Windows shutdown or restart machine
            if (CloseReason.UserClosing == e.CloseReason || true == closedByUser)
            {
                if (MessageBox.Show("Would you really want to terminate the workflow service?", "Trident Execution Tray app",
                        MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                {
                    e.Cancel = true;
                    closedByUser = false;
                }
            }
        }

        private void WFTrayForm_Load(object sender, EventArgs e)
        {
            this.Hide();
        }

        /// <summary>
        /// this function is used to log the message.
        /// </summary>
        /// <param name="level">Level.</param>
        /// <param name="message">Message to be logged.</param>
        private void Log(string level, string message)
        {
            Logger.Write(message, "FileLogger");
        }

        /// <summary>
        /// Log message received event handler.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnLogMessageReceived(object sender, LogEventArgs e)
        {
            this.Log(e.Level, e.Message);
        }
        #endregion

        #region Member Data

        private bool closedByUser;

        private WFServiceScheduler scheduler;

        private Thread scheduleThread;

        private Thread scheduleUpdaterThread;

        #endregion

        private void showAboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowAboutWindow();
        }
    }
}
